import os
import cv2
import numpy as np

# 检查并补充缺失的 x 坐标
def check_and_append(missing_coords, existing_coords, line_points_list, mean_y_int, threshold=10):
    for x in missing_coords:
        # 检查是否与现有坐标相差小于阈值
        if all(abs(x - existing_x) >= threshold for existing_x in existing_coords):
            # 如果相差大于等于阈值，则补充该坐标
            line_points_list.append((x, mean_y_int))

def get_image_paths(directory):
    image_extensions = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff'}
    image_paths = []

    for root, dirs, files in os.walk(directory):
        for file in files:
            if os.path.splitext(file)[1].lower() in image_extensions:
                image_paths.append(os.path.abspath(os.path.join(root, file)))

    return image_paths

# 筛选矩形轮廓并计算面积
def is_rectangle(cnt, params1):
    # 获取最小外接矩形
    rect = cv2.minAreaRect(cnt)
    width, height = rect[1]
    # print(width, height)
    # 确保宽高比在一定范围内（不是正方形）
    aspect_ratio = max(width, height) / min(width, height)

    # 判断是否为矩形（宽高比在1到2之间）
    return params1["min_ratio"] < aspect_ratio < params1["max_ratio"]

# 找到与 group_a 和 group_b 相关的点
def find_and_add_missing_points(group_a, group_b):
    for point_a in group_a:
        closest_point = None
        min_distance = float('inf')

        for point_b in group_b:
            # 检查 x 值差异
            if abs(point_a[0] - point_b[0]) <= 10:
                # 计算 y 坐标差异
                distance = np.sqrt((point_a[0] - point_b[0]) ** 2 + (point_a[1] - point_b[1]) ** 2)
                if distance < min_distance:
                    min_distance = distance
                    closest_point = point_b

        # 如果找到最近的点，补充到对应的组
        if closest_point is not None and closest_point not in group_a:
            group_a.append(closest_point)

def line_intersection(p1, p2, p3, p4):
    """
    计算两条直线的交点

    :param p1: 直线1的第一个点 (x1, y1)
    :param p2: 直线1的第二个点 (x2, y2)
    :param p3: 直线2的第一个点 (x3, y3)
    :param p4: 直线2的第二个点 (x4, y4)
    :return: 交点坐标 (x, y)，如果不相交则返回 None
    """

    x1, y1 = p1
    x2, y2 = p2
    x3, y3 = p3
    x4, y4 = p4

    # 计算直线的斜率和截距
    denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)

    # 检查是否平行
    if denom == 0:
        return None  # 两条直线平行或重合

    # 计算交点坐标
    x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denom
    y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denom

    return (x, y)


def get_area_around_point(img, ori_img, pnt, range_size=25, range_size2=15):
    """
    获取给定点周围的图像区域
        #50  40
    :param img: 输入图像
    :param pnt: 点坐标 (x, y)
    :param range_size: 范围大小
    :return: 指定区域的图像
    """

    x, y = pnt
    left = int(max(x - range_size, 0))
    right = int(min(x + range_size, img.shape[1]))
    top = int(max(y - range_size2, 0))
    bottom = int(min(y + range_size2, img.shape[0]))

    # 裁剪图像
    area = np.sum(img[top:bottom, left:right])

    max_area = 4 * range_size * range_size2 * 255  # 矩形全为白的面积理论最大值
    # 在原图上绘制红色矩形框
    cv2.rectangle(ori_img, (left, top), (right, bottom), (0, 0, 255), 2)  # 红色框
    # cv2.imwrite('D:\scoring-desktop-end\socre/saved_image5.jpg', ori_img)

    return area, max_area


def number_to_letter(num):
    """
    将数字转换为对应的字母

    :param num: 输入的数字 (1-26)
    :return: 对应的字母
    """
    if 1 <= num <= 26:
        return chr(num + 64)  # 'A' 的 ASCII 码是 65
    else:
        return None  # 超出范围的处理
# @handle_exceptions
def solve_1(img_path, standard_answers, subjectCode, studentId, paperId, answerQrcode, parentanswerid, vis=False):
    image = cv2.imread(img_path)
    height, width, _ = image.shape
    question_type = answerQrcode[0]

    processing_states = [22, 23, 18, 16, 17, 19, 20, 24, 1, 2, 3, 4, 21, 15, 20]
    # 由于15和20两种状态效果最好，但是在两侧的标记点识别上存在差异
    # 故设置一个标志位，来决定当状态15执行不通过时，重新调用状态20来输出结果
    sign = False
    # 灰度化
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    for state in processing_states:
        if state == 21:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.2,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 165)

            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)
            # cv2.imwrite('D:\scoring-desktop-end\socre/saved_image7.jpg', thresh_denoised)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 84)

            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
            # cv2.imwrite('D:\scoring-desktop-end\socre/saved_image6.jpg', thresh_denoised2)
        elif state == 24:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.2,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 140)

            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 84)

            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 23:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.2,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 180)

            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 97)

            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 22:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.2,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 170)

            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 84)

            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)

        elif state == 18:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.2,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            # thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 170)
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 150)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 94)

            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)

        elif state == 20:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.4,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            # thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 170)
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 155)

            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)
            # cv2.imwrite(r'D:\scoring-desktop-end\socre\saved_image7.jpg', thresh_denoised)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 2)  # 高斯模糊
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 64)

            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((15, 15), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
            # cv2.imwrite(r'D:\scoring-desktop-end\socre\saved_image6.jpg', thresh_denoised2)

        elif state == 19:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.2,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 175)

            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 94)

            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 13:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 10,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.3,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 170)

            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 2)  # 高斯模糊
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 101)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 17:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 2.0,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.3,  # 选项的填涂面积最小阈值
            }
            blurred = gray

            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 150)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 2)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV, 99, 101)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 2:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.4,  # 选项的填涂面积最小阈值
            }
            blurred = gray

            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 180)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 64)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)

        elif state == 3:
            # print(3)
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.4,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 125)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            # 降噪 - 使用高斯模糊
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 2)  # 高斯模糊
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 64)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((15, 15), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 4:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 10,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.2,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 145)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 74)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)

        elif state == 7:
            # print(1)
            params1 = {
                "min_area": 200,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.0,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 200,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 10,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 10,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.5,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 150)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            blurred_denoised = cv2.GaussianBlur(blurred, (7, 7), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 7)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((19, 19), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 5:
            params1 = {
                "min_area": 260,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 1.8,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 200,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 25,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 10,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.5,  # 选项的填涂面积最小阈值
            }
            blurred = cv2.GaussianBlur(gray, (13, 13), 0)
            thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
            # 进行去噪，使用形态学操作（例如开运算）
            kernel = np.ones((7, 7), np.uint8)
            thresh_denoised = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
            thresh_denoised2 = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
        elif state == 6:
            # print(6)
            params1 = {
                "min_area": 600,  # 标记的最小面积阈值
                "min_ratio": 1.6,  # 判断矩形的最小长宽比
                "max_ratio": 3.0,  # 判断矩形的最大长宽比
                "diff_area": 200,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 25,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 10,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 300000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.25,  # 选项的填涂面积最小阈值
            }
            blurred = cv2.GaussianBlur(gray, (13, 13), 0)
            thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
            # 进行去噪，使用形态学操作（例如开运算）
            kernel = np.ones((7, 7), np.uint8)
            thresh_denoised = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
            thresh_denoised2 = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
        elif state == 8:
            params1 = {
                "min_area": 200,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 205,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 10,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 10,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0, # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.5,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 158)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)
            #去噪
            blurred_denoised = cv2.GaussianBlur(blurred, (7, 7), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 7)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((21, 21), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 9:
            params1 = {
                "min_area": 200,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 10,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 10,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0, # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.6,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 158)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            #去噪
            blurred_denoised = cv2.GaussianBlur(blurred, (7, 7), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 7)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((21, 21), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 10:
            params1 = {
                "min_area": 200,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 10,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.5,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 152)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            #去噪
            blurred_denoised = cv2.GaussianBlur(blurred, (9, 9), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 75)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)

        elif state == 11:
            params1 = {
                "min_area": 200,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 10,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.5,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 150)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            #去噪
            blurred_denoised = cv2.GaussianBlur(blurred, (7, 7), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 7)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 12:
            params1 = {
                "min_area": 200,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 10,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.7,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 160)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            #去噪
            blurred_denoised = cv2.GaussianBlur(blurred, (7, 7), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 7)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 1:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.2,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 170)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            #去噪
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 94)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 14:
            params1 = {
                "min_area": 200,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.0,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 160,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 10,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.5,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            blurred_denoised = cv2.GaussianBlur(blurred, (7, 7), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 187, 83)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((10, 10), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            #去噪
            blurred_denoised = cv2.GaussianBlur(blurred, (7, 7), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 7)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((17, 17), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)

        elif state == 15:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.4,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            # blurred_denoised = cv2.GaussianBlur(blurred, (3, 3), 2)  # 高斯模糊，核大小为 (7, 7)
            # thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 187, 83)
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 180)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            #去噪
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 64)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((15, 15), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)
        elif state == 16:
            params1 = {
                "min_area": 220,  # 标记的最小面积阈值
                "min_ratio": 0.5,  # 判断矩形的最小长宽比  #标记点
                "max_ratio": 3.5,  # 判断矩形的最大长宽比  #标记点
                "diff_area": 220,  # 用于查找标记的面积差值允许范围，当两两面积之差小于diff_area则归为标记
                "y_threshold": 20,  # y轴距离阈值，用于判断多个点是否在同一水平直线上，y_threshold为多个点的y值差值的最大阈值
                "x_threshold": 25,  # x轴距离阈值，用于处理过滤掉超过2个标记但不是横向标记的问题（那正常的2标记横向两点的x轴与问题点集进行过滤）
                "min_error": 20,  # 纵向来看，左右两边的两两标记间距之间的差距允许最小误差
                "threshold_2": 500000,  # 用于判断选择题是否填涂，当某位置的面积小于max_area - threshold_2时表示未填涂，max_area为所有位置最大面积
                "threshold_3": 150000,  # 用于判断选择题是否填涂，从原始填涂的面积角度直接判断的最小面积阈值
                "threshold_4": 0,  # 用于判断是否存在选项，如果没有选项则视为指定列不存在问题
                "area_ratio": 0.65,  # 选项的填涂面积最小阈值
            }
            blurred = gray
            thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 180)
            # 定义膨胀的结构元素
            kernel_3 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated = cv2.dilate(thresh, kernel_3, iterations=1)
            thresh = dilated
            kernel1 = np.ones((1, 1), np.uint8)
            kernel = np.ones((8, 8), np.uint8)
            thresh_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel1)
            thresh_denoised = cv2.morphologyEx(thresh_closed, cv2.MORPH_OPEN, kernel)

            #去噪
            blurred_denoised = cv2.GaussianBlur(blurred, (13, 13), 3)  # 高斯模糊，核大小为 (7, 7)
            thresh2 = cv2.adaptiveThreshold(blurred_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 99, 64)
            # 定义膨胀的结构元素
            kernel_32 = np.ones((0, 0), np.uint8)  # 可以调整大小
            # 进行膨胀操作
            dilated2 = cv2.dilate(thresh2, kernel_32, iterations=1)
            thresh2 = dilated2
            kernel12 = np.ones((11, 11), np.uint8)
            kernel2 = np.ones((15, 15), np.uint8)
            thresh_closed2 = cv2.morphologyEx(thresh2, cv2.MORPH_CLOSE, kernel12)
            thresh_denoised2 = cv2.morphologyEx(thresh_closed2, cv2.MORPH_OPEN, kernel2)

        if vis:
            cv2.imshow('Marked Image', thresh_denoised)
            cv2.waitKey(0)
            cv2.destroyAllWindows()

        # 提取轮廓
        contours, _ = cv2.findContours(thresh_denoised, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        # # 绘制轮廓，-1 表示绘制所有轮廓，(0, 255, 0) 是绿色，2 是轮廓线的厚度
        cv2.drawContours(image, contours, -1, (0, 255, 0), 2)

        # 计算面积并排序
        areas = [(cv2.contourArea(cnt), cnt) for cnt in contours if cv2.contourArea(cnt) > params1["min_area"] and is_rectangle(cnt, params1)]
        areas.sort(key=lambda x: x[0])

        # 寻找最大集合
        max_count = 0
        max_group = []
        for i in range(len(areas)):
            current_group = [areas[i][1]]
            for j in range(i + 1, len(areas)):
                if abs(areas[j][0] - areas[i][0]) <= params1["diff_area"]:
                    current_group.append(areas[j][1])
                else:
                    break
            if len(current_group) > max_count:
                max_count = len(current_group)
                max_group = current_group

        # 假设 max_group 是之前已经定义的轮廓列表
        centroids = []
        for cnt in max_group:
            M = cv2.moments(cnt)
            if M['m00'] != 0:  # 防止除以零
                cX = int(M['m10'] / M['m00'])
                cY = int(M['m01'] / M['m00'])
                # 这里质点横坐标大于30的目的是避免题目左上角和左下角经过处理后对质点选择的影响
                if cX > 30:
                    centroids.append((cX, cY))
                # 在图像上标记质心
                cv2.circle(image, (cX, cY), 5, (0, 255, 0), -1)  # 绿色标记质心
                # cv2.imwrite('D:\scoring-desktop-end\socre/saved_image2.jpg', image)
        # print(centroids)
        # 判断图像处理后识别的质心数量是否为0
        if len(centroids) == 0:
            print("质心数量为0")
            continue
        # 显示结果
        if vis:
            cv2.imshow('Image with Centroids', image)
            cv2.waitKey(0)
            cv2.destroyAllWindows()
            # 输出质心坐标
            print("Centroids of max_group:", centroids)

        y_threshold = params1["y_threshold"]  # y轴距离阈值
        x_threshold = params1["x_threshold"]
        line_points = []

        # 遍历 centroids 列表
        visited = [False] * len(centroids)  # 标记已访问的点

        for i in range(len(centroids)):
            if visited[i]:
                continue  # 跳过已访问的点

            current_point = centroids[i]
            line_group = [current_point]  # 存储当前点及与其满足条件的点
            visited[i] = True  # 标记为已访问
            # print(line_group)
            for j in range(i + 1, len(centroids)):
                # 计算 y 坐标差异
                # abs(current_point[0] - centroids[j][0]) > 70  原
                if abs(current_point[1] - centroids[j][1]) < y_threshold and abs(current_point[0] - centroids[j][0]) > 25:
                    line_group.append(centroids[j])
                    visited[j] = True  # 标记为已访问

            # 如果找到了符合条件的点，则加入 line_points
            if len(line_group) > 1:  # 至少两个点才构成一条线
                line_points.append(line_group)
                # print(f"line_group1:{line_group}")

                # 绘制绿色线条
                for k in range(len(line_group) - 1):
                    pt1 = line_group[k]
                    pt2 = line_group[k + 1]
                    cv2.line(image, pt1, pt2, (0, 255, 0), 2)  # 绘制绿色线条
                # 保存图像到文件
                # cv2.imwrite('D:\scoring-desktop-end\socre/saved_image.jpg', image)

                # 计算线段中点位置来添加文本
                mid_x = (line_group[0][0] + line_group[-1][0]) // 2
                mid_y = (line_group[0][1] + line_group[-1][1]) // 2
                cv2.putText(image, f"Line group {len(line_points)}", (mid_x, mid_y),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 255), 1)

        group_a, group_b, h_list, other_list = None, None, [], []

        # 判断是否存在可以连线的质心
        if len(line_points) == 0:
            print("不存在可以连线的质心")
            continue
        # 获取最长列表的长度
        max_length = max(len(points) for points in line_points)
        # 按照每个组的长度进行排序，长度长的组在前
        line_points = sorted(line_points, key=len, reverse=True)
#25510110111203
        # print(line_points,"_+_+_+_+")
        if len(line_points) >= 5:
            if max_length % 5 == 0:
                max_length_true = max_length
            elif max_length % 5 != 0:
                if (max_length % 5) <= 1:
                    max_length = max_length - (max_length % 5)
                    line_points[0] = sorted(line_points[0], key=lambda point: point[0])
                    line_points[1] = sorted(line_points[1], key=lambda point: point[0])
                    if abs(line_points[0][0][0] - line_points[1][0][0]) > 10:
                        # print("删除左边多余的点")
                        del line_points[0][0]
                    if abs(line_points[0][-1][0] - line_points[1][-1][0]) > 10:
                        # print("删除右边多余的点")
                        del line_points[0][-1]
                else:
                    # 这里将上下两排标记点进行计算互补，提高标记点识别的容错率
                    # 提取两个列表中的x坐标
                    x_coords_1 = set(item[0] for item in line_points[0])
                    x_coords_2 = set(item[0] for item in line_points[1])
                    # 提取y坐标
                    y_coords_0 = [point[1] for point in line_points[0]]
                    y_coords_1 = [point[1] for point in line_points[1]]
                    # 计算y坐标的均值
                    mean_y_0 = sum(y_coords_0) / len(y_coords_0)
                    mean_y_1 = sum(y_coords_1) / len(y_coords_1)
                    # 取整均值
                    mean_y_0_int = round(mean_y_0)
                    mean_y_1_int = round(mean_y_1)
                    # 找出两个列表中缺失的x坐标
                    missing_in_list1 = x_coords_2 - x_coords_1
                    missing_in_list2 = x_coords_1 - x_coords_2
                    # 补充缺失的 x 坐标到第一个列表
                    check_and_append(missing_in_list1, x_coords_1, line_points[0], mean_y_0_int)
                    # 补充缺失的 x 坐标到第二个列表
                    check_and_append(missing_in_list2, x_coords_2, line_points[1], mean_y_1_int)
                    # 重新设置标记点的最大长度
                    max_length = len(line_points[0])

        # 输出符合条件的点
        for idx, group in enumerate(line_points):
            # if len(group) == 6:
            #     group = group[:5]
            #     max_length = 5
            #     if len(group) == max_length:
            #         if group_a is None:
            #             group_a = group
            #         else:
            #             group_b = group
            #     else:
            #         if len(group) == 2:
            #             h_list.append(group)
            #         else:
            #             other_list.append(group)
            # else:
            if len(group) == max_length:
                if group_a is None:
                    group_a = group
                else:
                    if group != group_a:
                        group_b = group
            elif len(group) + 2 == max_length and group_b is None and group_a is not None:
                # 按照 x 坐标对点进行排序
                group = sorted(group, key=lambda point: point[0])
                group_a = sorted(group_a, key=lambda point: point[0])
                # 计算 group 中的 y 轴坐标平均值
                y_values = [point[1] for point in group]
                y_average = sum(y_values) / len(y_values)
                # 将 group_a 中的 y 轴坐标替换为 y 轴坐标平均值，并赋值给 group_b
                group_b = [(point[0], y_average) for point in group_a]
            elif len(group) + 1 == max_length and group_b is None and group_a is not None:
                # 按照 x 坐标对点进行排序
                group = sorted(group, key=lambda point: point[0])
                group_a = sorted(group_a, key=lambda point: point[0])
                # 计算 group 中的 y 轴坐标平均值
                y_values = [point[1] for point in group]
                y_average = sum(y_values) / len(y_values)
                # 将 group_a 中的 y 轴坐标替换为 y 轴坐标平均值，并赋值给 group_b
                group_b = [(point[0], y_average) for point in group_a]
            elif max_length - len(group) <= 3 and group_b is None and group_a is not None:
                # 按照 x 坐标对点进行排序
                group = sorted(group, key=lambda point: point[0])
                group_a = sorted(group_a, key=lambda point: point[0])
                # 计算 group 中的 y 轴坐标平均值
                y_values = [point[1] for point in group]
                y_average = sum(y_values) / len(y_values)
                # 将 group_a 中的 y 轴坐标替换为 y 轴坐标平均值，并赋值给 group_b
                group_b = [(point[0], y_average) for point in group_a]
            elif max_length - len(group) <= 8 and group_b is None and group_a is not None and state == 15:
                # 按照 x 坐标对点进行排序
                group = sorted(group, key=lambda point: point[0])
                group_a = sorted(group_a, key=lambda point: point[0])
                # 计算 group 中的 y 轴坐标平均值
                y_values = [point[1] for point in group]
                y_average = sum(y_values) / len(y_values)
                # 将 group_a 中的 y 轴坐标替换为 y 轴坐标平均值，并赋值给 group_b
                group_b = [(point[0], y_average) for point in group_a]
            else:
                # 收集两侧标记点
                if len(group) == 2:
                    h_list.append(group)
                else:
                    other_list.append(group)

            if vis:
                print(f"Line group {idx + 1}: {group}")

        # 判断两侧的标记点数量是否小于1
        if len(h_list) == 0:
            print("未识别到两侧标记点")
            continue

        # 先对每个子列表内部的元组按照 x 轴坐标进行排序
        sorted_sublists = [sorted(sublist, key=lambda item: item[0]) for sublist in h_list]
        # 按照每个子列表中第一个元组的第一个值（x轴坐标）进行排序
        h_list = sorted(sorted_sublists, key=lambda item: item[0][0])
        # 设置阈值
        threshold = 10  # 你可以根据需要调整这个值
        # 获取第一个元组的 x 轴坐标
        first_x = h_list[0][0][0]
        # 遍历列表，将不符合条件的 x 轴坐标修改为最小的 x 轴坐标
        for item in h_list:
            if abs(item[0][0] - first_x) > threshold:
                item[0] = (first_x, item[0][1])

        # 过滤掉超过2个标记但不是横向标记的问题
        x_threshold = params1["x_threshold"]
        if len(other_list) != 0:
            for group in other_list:
                # 找到 x 坐标最小的点
                min_point = min(group, key=lambda point: point[0])
                # 找到 x 坐标最大的点
                max_point = max(group, key=lambda point: point[0])
                # 将最小和最大的点添加到 filtered_list 中
                group = [min_point, max_point]
                filtered_points = [
                    point for point in group
                    if any(abs(point[0] - h[0]) < x_threshold for h in h_list[0])
                ]
                if len(filtered_points) == 2:
                    h_list.append(group)

        # 判断两侧的标记点数量是否小于1
        if len(h_list) <= 1:
            print("两侧标记点数量识别数量过低")
            continue
        # 判断上下的标记点是否识别
        if group_a is None or group_b is None:
            print("上下的标记点未识别到")
            continue
        # 判断上下识别到的标记点数量是否一致
        if len(group_a) != len(group_b):
            print("上下识别到的标记点数量不一致")
            continue

        group_a = sorted(group_a, key=lambda point: point[0])
        group_b = sorted(group_b, key=lambda point: point[0])
        # 首先对内部的小列表按 x 值排序
        for sublist in h_list:
            sublist.sort(key=lambda point: point[0])

        # 然后对外部列表按小列表第一个元素的 y 值排序
        h_list.sort(key=lambda sublist: sublist[0][1])

        # print(f"groupa:{group_a}")
        # print(f"groupb:{group_b}")
        # print(f"h_list:{h_list}")

        # 逐个检查并删除不符合条件的元组
        while len(h_list) > 2:  # 确保列表中有足够的元组进行比较
            first_y = h_list[0][0][1]
            second_y = h_list[1][0][1]
            diff_first = abs(first_y - second_y)
            # print(f"idx:0,diff_first:{diff_first}")
            # 删除同组中与其他坐标差值过大的坐标点
            if diff_first > 100:
                del h_list[0]
                continue  # 删除后重新从头检查

            for idx in range(1, len(h_list) - 1):
                prev_y = h_list[idx - 1][0][1]
                curr_y = h_list[idx][0][1]
                next_y = h_list[idx + 1][0][1]

                # 计算当前元组与前后元组的 y 轴坐标差值
                diff_prev = abs(curr_y - prev_y)
                diff_next = abs(curr_y - next_y)

                # 如果当前元组与前后元组的差值都大于阈值，则删除该元组
                if 0 < diff_prev < 10 or 0 < diff_next < 10:
                    del h_list[idx]
                    break  # 删除后重新从头检查
            else:  # 如果没有找到需要删除的元组，则退出循环
                break
        # print(h_list)

        if vis:
            print(f"group_a: {group_a}")
            print(f"group_b: {group_b}")
            print(f"h_list: {h_list}")
        # 存储需要删除的索引
        to_delete = []
        # dist_lst表示每行之间的距离
        dist_lst = np.zeros(len(h_list) - 1)
        for idx in range(len(h_list) - 1):
            dist_lst[idx] = h_list[idx + 1][0][1] - h_list[idx][0][1]
            if dist_lst[idx] == 0:
                to_delete.append(idx)
        # 从后向前删除，以避免索引变化导致的问题
        for idx in sorted(to_delete, reverse=True):
            del h_list[idx]

        # 移除所有 0 的元素
        dist_lst = [item for item in dist_lst if item != 0.0]
        # 拿第一行与第二行之间的间距作为对比标准
        n_answer_lst = []

        # 判断识别到的纵向标记点的数量是否过少
        if len(dist_lst) == 0:
            print("纵向标记点识别过少")
            continue

        # print(dist_lst)
        view = dist_lst[0]
        now_list = [1]
        for idx in range(len(h_list) - 1):
            if abs(dist_lst[idx] - view) <= params1["min_error"]:
                now_list.append(idx + 2)
            else:
                n_answer_lst.append(now_list)
                now_list = []  # 重置now_list
                # idx + 2只有在now_list为空时才添加，因为now_list已经重置为空
                now_list.append(idx + 2)
        if len(now_list) != 0:
            n_answer_lst.append(now_list)
        # print(f"n_answer_list: {n_answer_lst}")

        # 检查所有子列表的长度是否相等
        all_equal = all(len(group) == len(n_answer_lst[0]) for group in n_answer_lst)
        if all_equal:
            pass
        else:
            if state == 15:
                sign = True
            print("每部分的选项数量不一致")
            continue

        # 答题卡的题数，选项的个数
        n_question, n_answer = len(group_a), len(h_list)
        # print(f"n_question: {n_question}, n_answer: {n_answer}")

        answers = []
        max_area = 0
        area_sums = np.zeros((n_question, n_answer))
        for idx in range(n_question):
            for l_idx, now_list in enumerate(n_answer_lst):
                for h in range(len(now_list)):
                    try:
                        pnt = line_intersection(h_list[now_list[h] - 1][0], h_list[now_list[h] - 1][1], group_a[idx], group_b[idx])
                        # print(pnt,"||||||||||||||||||||||")
                        if pnt is not None:
                            area, max_area = get_area_around_point(thresh_denoised2, image, pnt)
                        else:
                            area = 0
                            max_area = 0
                    except Exception as e:
                        print(f"An error occurred: {e}")
                    if vis:
                        print(f"ratio: {area / m_area}")
                    max_area = max(max_area, area)
                    area_sums[idx][now_list[h] - 1] = area
                    if vis:
                        print(f"n_question_{idx + 1}, n_answer_{h + 1}: {area}")

        threshold_2 = params1["threshold_2"]
        threshold_3 = params1["threshold_3"]
        threshold_4 = params1["threshold_4"]
        if vis:
            print(f"max_area: {max_area}, {max_area - threshold_2}")
        # lock = False  # 判断是否是多选题

        for l_idx, now_list in enumerate(n_answer_lst):
            for idx in range(n_question):
                pnt2 = []
                answer = ""
                judge = False  # 判断是否是空白的
                lock = False  # 判断是否是多选题
                for h in range(len(now_list)):
                    now_area = area_sums[idx][now_list[h] - 1]
                    pnt = line_intersection(h_list[now_list[h] - 1][0], h_list[now_list[h] - 1][1], group_a[idx],
                                            group_b[idx])
                    if pnt is not None:
                        area, m_area = get_area_around_point(thresh_denoised2, image, pnt)
                        ratio = area / m_area
                    else:
                        ratio = 0
                        print("pnt为空")
                    # print(ratio)
                    # # 提取每个元组的第三个元素（字母）
                    # letters = [item[2] for item in standard_answers]
                    # print(7965)
                    # # 使用set来找出所有不同的字母
                    # unique_letters = set(letters)
                    # # 对不同字母进行排序
                    # sorted_unique_letters = sorted(unique_letters)
                    # # 找到排序后的最后一个字母
                    # last_letter = sorted_unique_letters[-1]
                    # # 将最后一个字母转换成数字
                    # number = ord(last_letter) - ord('A') + 1
                    # print(f"字母有:{unique_letters}")
                    # # # 打印不同字母的种类数量
                    # # print(f"字幕的种类有 {len(unique_letters)} 种")
                    if question_type != 3 and len(now_list) == 2:
                        # print(1234)
                        break
                    if ratio >= params1["area_ratio"]:
                        if len(now_list) == 2 and question_type == 3:  # 判断题
                            pnt2.append(pnt)
                            if h == 0:
                                answer += "T"
                            elif h == 1:
                                answer += "F"
                        else:
                            tmp = number_to_letter(h + 1)
                            if tmp is not None:
                                pnt2.append(pnt)
                                if answer:  # 如果 answer 不为空
                                    answer += ","  # 添加逗号和空格
                                answer += tmp  # 添加字母到 answer

                    if now_area >= threshold_4:
                        judge = True

                if lock == True:
                    break

                if idx + l_idx * n_question < len(standard_answers):
                    if len(standard_answers[idx + l_idx * n_question][2]) == 1 and len(answer) != 1:
                        if state != 15 and sign == False:
                            lock = True
                            break
                        else:
                            print(answer)
                            answer = ''

                if question_type != "2" and len(answer) > 1:
                    if state != 15:
                        lock = True
                        break
                # print(state)
                if judge:
                    # print(state)
                    # print(f"answer:{answer}")
                    # print(f"idx:{idx+l_idx*n_question}")
                    # print(f"len(standard_answers):{len(standard_answers)}")
                    if idx + l_idx * n_question < len(standard_answers):
                        if answer == "":
                            pnt2 = []
                            answers.append((standard_answers[idx + l_idx * n_question][0], subjectCode, studentId, standard_answers[idx + l_idx * n_question][2], paperId, pnt2, None, standard_answers[idx + l_idx * n_question][1], standard_answers[idx + l_idx * n_question][3]))
                        else:
                            answers.append((standard_answers[idx + l_idx * n_question][0], subjectCode, studentId, standard_answers[idx + l_idx * n_question][2], paperId, pnt2, answer, standard_answers[idx + l_idx * n_question][1], standard_answers[idx + l_idx * n_question][3]))
                    else:
                        pass
                else:
                    break
            if lock:
                lock = True
                break
        # 当单选题识别到多个选项时，跳出循环执行下一个状态
        if lock:
            print("单选题多识别到选项")
            continue
        if vis:
            cv2.imshow('Marked Image', image)
            cv2.waitKey(0)
            cv2.destroyAllWindows()

        return answers


